#include "defs.h"
#include <stddef.h>  //NULL定义

struct run {
  struct run *next;
};

struct {
  struct spinlock lock;
  struct run *freelist;
} kmem;

extern char end[];  // 指向内核数据段结束位置

// 调试用：打印内存初始化信息
void print_memory_info() {
  printf("Memory initialization info:\n");
  printf("  end = %p\n", end);
  printf("  PHYSTOP = %p\n", (void*)PHYSTOP);
  printf("  PGSIZE = %d\n", PGSIZE);
}

void kinit() {
  initlock(&kmem.lock, "kmem");
  
  // 打印内存信息帮助调试,其实并未实现
  print_memory_info();
  
  //数据段向上对齐找到第一个可用页的位置
  char *p = (char*)PGROUNDUP((uint64)end);
  
  // 检查是否有可用内存
  if (p + PGSIZE > (char*)PHYSTOP) {
    panic("No available physical memory for allocation");
  }
  
  // 将所有可用物理页加入空闲链表
  for (; p + PGSIZE <= (char*)PHYSTOP; p += PGSIZE) {
    free_page(p);
  }
  
  // 验证空闲链表是否初始化成功
  acquire(&kmem.lock);
  if (kmem.freelist == NULL) {
    release(&kmem.lock);
    panic("Failed to initialize free memory list");
  }
  release(&kmem.lock);
}

//增加空闲页,初始化添加或者后期释放
void free_page(void *pa) {
  struct run *r;

  // 验证地址合法性
  if (((uint64)pa % PGSIZE) != 0)
    panic("free_page: address not page-aligned");//没对齐
  if ((char*)pa < end)
    panic("free_page: address below kernel end");//占用数据段
  if ((uint64)pa >= PHYSTOP)
    panic("free_page: address above PHYSTOP");//超过可用空间

  // 填充内存为0xaa，便于检测使用已释放内存的错误
  memset(pa, 0xaa, PGSIZE);

  r = (struct run*)pa;

  acquire(&kmem.lock);
  r->next = kmem.freelist;
  kmem.freelist = r;
  release(&kmem.lock);
}

//分配空闲页
void *alloc_page() {
  struct run *r;

  acquire(&kmem.lock);
  r = kmem.freelist;
  if (r) {
    kmem.freelist = r->next;  //空闲页先分配head
  } else {
    printf("alloc_page: no free pages available\n");
  }
  release(&kmem.lock);

  if (r) {
    // 填充内存为0x55，标记为已分配
    memset((char*)r, 0x55, PGSIZE);
  }
  return (void*)r;
}

//统计现有的空闲页个数：内存0x55表示已经分配，非空闲页，0xaa为空闲页，直接遍历空闲链表
int count_free_pages() {
    int count = 0;
    struct run *r;

    // 加锁保护空闲链表
    acquire(&kmem.lock);

    // 从空闲链表头开始遍历
    r = kmem.freelist;
    while (r != NULL) {
        count++;
        r = r->next;  
    }

    // 释放锁
    release(&kmem.lock);

    return count;
}